﻿/*
 * Created by SharpDevelop.
 * User: Hellen(LongFan)
 * Date: 2015-11-23
 * Time: 18:40
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.IO.Ports;
using System.Threading;			//多线程
using System.Windows.Forms;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
//LibUsbDotNet
using LibUsbDotNet;
using LibUsbDotNet.Main;
using LibUsbDotNet.Info;
using LibUsbDotNet.Descriptors;
using LibUsbDotNet.LibUsb;
using LibUsbDotNet.WinUsb;

namespace Comm
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	
	//main form
	public partial class MainForm : Form
	{
		//Driver Start Frequence, and Driver delta frequence
		public static UInt16 DriveStartFreq = 10;
		public static int DriveDeltaFreq = 0;
		//data queue
		public static ConcurrentQueue<byte> MyReDataQueue = new ConcurrentQueue<byte>();	
		//public static bool ShowCurve = false;
			
		private UInt16 OldDriverStartFreq = 10;
		private int OldDriveDeltaFreq = 0;
		//Folder size, if bigger than FOLDERSIZER, warning to delete
		private const int FOLDERSIZER  = 800;	
		private long NumberOfCurvePoint = 800 ;		
		//the bytes want to send
		private byte[] BytesToWrite;
		private byte[] BytesWrite = new byte[12];
		
		private string DirPaht = @".\Data";
		private string FilePath = @".\Data\";
		private FileStream MyCSVFS = null;
		private StreamWriter MyCSVWS = null;
		
		private MyCommClass MyComm = new MyCommClass();
		private DealDataThread MyDealDataTh = new DealDataThread();
		private UpdataCurveThreadClass MyUpdataCurveTh = new UpdataCurveThreadClass();
	
		public MainForm()
		{
			long len = 0;
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			
			//
			// TODO: Add constructor code after the InitializeComponent() call.
			//
			//Add serialport received event
			MyComm.MySerialPort.DataReceived += new SerialDataReceivedEventHandler(MyComm.MySerialPort_DataReceived);
			//Thread Invoke delegate
			MyDealDataTh.MyUpdataInvokeDelegate = new DealDataThread.UpdataInterFaceInvokeDelegate(HandleUpdataInterFace);
			//Updata curve thread invoke delegate
			MyUpdataCurveTh.UpdataCurveInvokeHandle = new UpdataCurveThreadClass.UpdataCurveEventHandle(HandleUpdataCurve);
			
        	//if no direct, creat directory
 			if(!Directory.Exists(DirPaht))
        	{
 				Directory.CreateDirectory(DirPaht);
 			}
 			else
 			{//check the folder size
 				DirectoryInfo di = new DirectoryInfo(DirPaht);
 				foreach( FileInfo fi in di.GetFiles() )
 				{
 					len += fi.Length;		//the len is (byte)
 				}
 				if( FOLDERSIZER < len/1048576)
 				{//if the size bigger than 300MB
 					DialogResult dr = MessageBox.Show("The folder size is bigger than 300MB, do you want dlete all files in the folder?\n" +
 					                "文件夹大小超过300MB，是否清空文件夹？", "Warning", MessageBoxButtons.YesNo);
 					if( dr == DialogResult.Yes)
 					{//delete the files
 						try
 						{
 							Directory.Delete(DirPaht,true);
 						}
 						catch(Exception ex)
 						{
 							MessageBox.Show(ex.ToString());
 						}
 						Directory.CreateDirectory(DirPaht);
 					}
 				}
 			}
 			FreqToolStripStatusLabel.Text = " |DriveFreq: 10 Hz";
 			PointsComboBox.SelectedIndex = 2;
		}
		
		
		void Button1Click(object sender, EventArgs e)
		{
			 
		}
		//updata the interface handle function
		private void HandleUpdataInterFace(string s)
		{
			if(rxDataShow.InvokeRequired)
			{
				this.Invoke(MyDealDataTh.MyUpdataInvokeDelegate,  new object[]{s} );
			}
			else
			{	//refresh the read count
				ReadCountToolStripStatusLabel.Text = (MyCommClass.ReceivedCount).ToString();
				//refresh the text show
				//rxDataShow.AppendText(String.Format("0x{0:x} ",int.Parse(s)));
				rxDataShow.AppendText(s);
//				if(ShowCurve)
//				{
//					//refresh the curve
//					DataChart.Series["Voltage"].Points.AddY((Convert.ToSingle(s)/65536)*5);
//				}
			}
			
		}
		//updata curve handle function
		private void HandleUpdataCurve(Double Ydata)
		{
			if(DataChart.InvokeRequired)
			{
				this.Invoke(MyUpdataCurveTh.UpdataCurveInvokeHandle, new object[]{Ydata});
			}
			else
			{//updata curve
				if( NumberOfCurvePoint < DataChart.Series["Voltage"].Points.Count)
				{//only show shome point, if too large, the UI will slowly
					DataChart.Series["Voltage"].Points.RemoveAt(0);
					DataChart.Series["Voltage"].Points.AddY(Ydata);
				}
				else
				{
					DataChart.Series["Voltage"].Points.AddY(Ydata);
				}
			}
		}
		
		void 设置串口ToolStripMenuItemClick(object sender, EventArgs e)
		{
			ConfigForm MyConfComm = new ConfigForm();
			//Add event
			MyConfComm.ConfCommEvent += new MyConfigCommEventHandler(ConfigCommHandler);
			MyConfComm.Owner = this;
			MyConfComm.ShowDialog();			
		}
		
		void 参数设置ToolStripMenuItemClick(object sender, EventArgs e)
		{
			 ConfigPara NewConfParaForm = new ConfigPara();
			 NewConfParaForm.ConfirmParaEvent += new MyConfirmParaEventHandler(ConfirmParaHandler);
			 NewConfParaForm.Owner = this;
			 NewConfParaForm.ShowDialog();
		}
		//
		private void ConfigCommHandler(object sender, EventArgs e)
		{
			string StopBString = "";
			string ParityString = "";

			//set comm parity,stopbit setting
			switch(MyCommClass.SParity)
			{//Parity
				case 0:
					ParityString = "None";
					break ;
				case 1:
					ParityString = "Odd";
					break ;
				case 2:
					ParityString = "Even";
					break ;
				default :
					ParityString = "None";
					break ;					
			}
			switch(MyCommClass.SStopBits)
			{//Stop bit
				case 0:
					StopBString = "1";
					break ;
				case 1:
					StopBString = "1.5";
					break ;
				case 2:
					StopBString = "2";
					break ;
				default :
					StopBString = "1";
					break ;					
			}
			toolStripStatusLabel1.Text = MyCommClass.SPortName + " "						//Comm status
										 + "( " + Convert.ToString(MyCommClass.SBaudRate) + ","
										 + Convert.ToString(MyCommClass.SByteSize) + ","
										 + ParityString + ","
										 + StopBString + " " +")" ;		//Driver frequence status
			//Open Comm, creat file
			MyComm.Open();
			if(MyCommClass.Opened)
			{//comm opened successed
				//creat save file
	 			FilePath += (DateTime.Now.ToString(@"M-d-yyyy-hh-mm-sstt") + Convert.ToString(DriveStartFreq + DriveDeltaFreq) + "Hz" + ".csv");
	 			MyCSVFS = new FileStream(FilePath,FileMode.Create,FileAccess.Write);
	 			MyCSVWS = new StreamWriter(MyCSVFS, System.Text.Encoding.UTF8); 
	 			MyCSVWS.WriteLine(Convert.ToString("DEC") + "," + Convert.ToString("HEX") + ",");					
				//Start the deal data thread but not start the deal data function, untile received
				//a data.
				MyDealDataTh.StartDealThread(ref MyCSVWS);
				//send frequence to control
				if( (OldDriveDeltaFreq != DriveDeltaFreq) || (OldDriverStartFreq != DriveStartFreq) )
				{
					//if the start frequence or delta frequence changed, write the configuration to MCU
					MyComm.Write(BytesWrite);
					OldDriverStartFreq = DriveStartFreq;
					OldDriveDeltaFreq = DriveDeltaFreq;
				}				
			}
			else
			{
				MessageBox.Show( "不能打开串口: " + MyCommClass.SPortName + "!" );
				return ;
			}
			//updata the ToolStripMenuItem
			开始采集ToolStripMenuItem.Enabled = false;
			端口设置ToolStripMenuItem.Enabled = false;
			参数设置ToolStripMenuItem.Enabled = false;
			//enable the show data and show curve menu
			ShowCurveToolStripMenuItem.Enabled = true;
			StopShowTextToolStripMenuItem.Enabled = true;
			停止采集ToolStripMenuItem.Enabled = true;	
			//clear the text box
			rxDataShow.Clear();			
		}
		
		private void ConfirmParaHandler(object sender, EventArgs e)
		{
			byte CrcTemp = 0;
			//Initial the bytewrite
			for( int i = 0 ; i<12 ; i++ )
			{
				BytesWrite[i] = 0;
			}
			//construct the write command--High byte send first(BigEndding), 16Bit aligned
			BytesWrite[0] = 0xAA;			//head
			BytesWrite[1] = 0x55;
			
			BytesWrite[2] = 12;				//length
			BytesWrite[3] = 0;				//aligned, reserved
			
			BytesWrite[4] = Convert.ToByte(DriveDeltaFreq & 0xFF);
			BytesWrite[5] = Convert.ToByte((DriveDeltaFreq & 0xFF00) >> 8 );
			BytesWrite[6] = Convert.ToByte((DriveDeltaFreq & 0xFF0000) >> 16 );
			BytesWrite[7] = Convert.ToByte((DriveDeltaFreq & 0xFF000000)>> 24 );
			
			BytesWrite[8] = Convert.ToByte(DriveStartFreq & 0xFF);				//16Bit aligned, so don`t should reserve short
			BytesWrite[9] = Convert.ToByte((DriveStartFreq & 0xFF00) >> 8 );
			
			BytesWrite[10] = 0;
			
			foreach(byte item in BytesWrite)
			{
				CrcTemp ^= item;
			}
			BytesWrite[11] = CrcTemp;
			//if is byte mode, enable the show mode chose
			if(DealDataThread.ByteFormat)
			{
				ShowStatusGroupBox.Enabled = true;
			}
			else
			{
				ShowStatusGroupBox.Enabled = false;
			}
			//Updata the tool status label
			FreqToolStripStatusLabel.Text = " |DriveFreq: " + 
											(DriveStartFreq + DriveDeltaFreq).ToString() +
											"Hz ";
		}
		
		public static void ResetDriverFreq()
		{//Reset frequence
			DriveDeltaFreq = 0;
			DriveStartFreq = 10;
		}
		
		void ContextMenuStrip1Opening(object sender, System.ComponentModel.CancelEventArgs e)
		{
			
		}
		
		void MainFormFormClosing(object sender, FormClosingEventArgs e)
		{
			//stop the data deal thread
			MyDealDataTh.StopDealThread();
			//close the comm
			if(MyCommClass.Opened)
			{
				while(!MyComm.Close())
					Application.DoEvents();
			}
			//close the filestream and streamwrite
			//if creat a file and opend, close it
			if(MyCSVWS != null)
			{
				MyCSVWS.Close();
			}
			if(MyCSVFS != null)
			{
				MyCSVFS.Close();
			}			
		}
		
		void 开始采集ToolStripMenuItemClick(object sender, EventArgs e)
		{
			if(MyCommClass.SPortName == "" || Convert.ToString(MyCommClass.SBaudRate) == "0")
			{
				MessageBox.Show("串口号和波特率必须先设置！");
				return ;
			}
			//Open Comm
			MyComm.Open();
			if(MyCommClass.Opened)
			{//Comm Opende successed
				//creat save file
	 			FilePath += (DateTime.Now.ToString(@"M-d-yyyy-hh-mm-sstt") + Convert.ToString(DriveStartFreq + DriveDeltaFreq) + "Hz" + ".csv");
	 			MyCSVFS = new FileStream(FilePath,FileMode.Create,FileAccess.Write);
	 			MyCSVWS = new StreamWriter(MyCSVFS, System.Text.Encoding.UTF8); 
	 			MyCSVWS.WriteLine(Convert.ToString("DEC") + "," + Convert.ToString("HEX") + ",");
				//Start deal data thread
	 			MyDealDataTh.StartDealThread(ref MyCSVWS);
				
				if( (OldDriveDeltaFreq != DriveDeltaFreq) || (OldDriverStartFreq != DriveStartFreq) )
				{//if the start frequence or delta frequence changed, write the configuration to MCU
					MyComm.Write(BytesWrite);
					OldDriverStartFreq = DriveStartFreq;
					OldDriveDeltaFreq = DriveDeltaFreq;
				}
			}
			else
			{
				MessageBox.Show( "不能打开串口: " + MyCommClass.SPortName + "!" );
				return ;
			}
			//updata toolstripmenu
			开始采集ToolStripMenuItem.Enabled = false;
			端口设置ToolStripMenuItem.Enabled = false;
			参数设置ToolStripMenuItem.Enabled = false;
			
			停止采集ToolStripMenuItem.Enabled = true;
			ShowCurveToolStripMenuItem.Enabled = true;
			StopShowTextToolStripMenuItem.Enabled = true;
			//clear the text box
			rxDataShow.Clear();
		}
		
		void 停止采集ToolStripMenuItemClick(object sender, EventArgs e)
		{
			byte[] tempByte = new byte[2];
			int tempInt = 0;
			int tempCount = 0;
			
			if(MyCommClass.Opened)
			{//if have a comm opened, close it
				while(!MyComm.Close())//wait the comm to close
					Application.DoEvents();
			}
			//stop Deal data thread while, close Comm, close file
			MyDealDataTh.StopDealThread();
			if(UpdataCurveThreadClass.DataToCurveQueueEn)
			{//if the updata curve thread is created
				MyUpdataCurveTh.StopUpadaCurveTh();	//stop curve thread
			}
			//Check if the queue have data, read the data
			try
			{
				tempCount = int.Parse(ReadCountToolStripStatusLabel.Text) ;
			}
			catch(Exception ex)
			{
				MessageBox.Show(Convert.ToString(ex));
			}
			
			if( !MyReDataQueue.IsEmpty )
			{
				if(DealDataThread.ByteFormat)
				{//Byte model
					while( !MyReDataQueue.IsEmpty )
					{
						tempCount += 1;
						MyReDataQueue.TryDequeue(out tempByte[0]);					
						MyCSVWS.WriteLine(	Convert.ToString(tempByte[0])+ ","
												+Convert.ToString(tempByte[0],8)+ ","
											);
					}
				}
				else
				{//word model
					while( 2 <= MyReDataQueue.Count )
					{
						tempCount += 2;
						MyReDataQueue.TryDequeue(out tempByte[1]);
						MyReDataQueue.TryDequeue(out tempByte[0]);
						tempInt = BitConverter.ToUInt16(tempByte,0);
								
						MyCSVWS.WriteLine( Convert.ToString(tempInt)+ "," 
												+Convert.ToString(tempInt,16)+ ","
											);
					}
					//Dequeue the last one data
					tempCount += 1;
					MyReDataQueue.TryDequeue(out tempByte[0]);					
					MyCSVWS.WriteLine( Convert.ToString(tempByte[0])+ "," 
											+Convert.ToString(tempByte[0],8)+ ","
										);
				}
			}
			//Updata the received count
			ReadCountToolStripStatusLabel.Text = tempCount.ToString();
			//if creat a file and opend, close it
			if(MyCSVWS != null)
			{
				MyCSVWS.Close();
			}
			if(MyCSVFS != null)
			{
				MyCSVFS.Close();
			}	
			//redirect the file path
			FilePath = @".\Data\";	
			
			//Updata the toolstripmenu
			开始采集ToolStripMenuItem.Enabled = true;		//open configuration
			端口设置ToolStripMenuItem.Enabled = true;
			参数设置ToolStripMenuItem.Enabled = true;
			//updata strip menu
			ShowCurveToolStripMenuItem.Text = "显示曲线";
			ShowCurveToolStripMenuItem.Enabled = false;
			StopShowTextToolStripMenuItem.Enabled = false;
			停止采集ToolStripMenuItem.Enabled = false;			
		}
		
		void 数据发送ToolStripMenuItemClick(object sender, EventArgs e)
		{
			if(!MyCommClass.Opened)
			{
				MessageBox.Show("Please Open a Port First!");
				return ;
			}
			//Creat the form
			SendDataForm MySendForm = new SendDataForm();
			//Add event
			MySendForm.MySendDataEvent += new MySendDataFromEventHandle(SendDataEventHandler);
			MySendForm.MySendFromClosedEvent += new MySendDataFromClosedEventHandle(SendFromClosedEventHandler);
			
			SendDataToolStripMenuItem.Enabled = false;
			MySendForm.Show();				
		}
		//Deal SendData Form send data event
		private void SendDataEventHandler(object sender, SendDataEventArgs e)
		{
			int SendCount = 0;
			List<byte> HexStrBytes = new List<byte>();

			SendCount = Encoding.UTF8.GetByteCount(e.SendString);
			//construct th bytes[] to write
			char[] HexBytes = e.SendString.ToCharArray();
			foreach(char c in HexBytes)
			{//force turn the char to byte, don`t use the Conver class and Encoding class
				HexStrBytes.Add((byte)c); 
			}
			BytesToWrite = HexStrBytes.ToArray();
				
			if(SendDataForm.AutoSendStatus)
			{//If Auto Send is enabled, start a thread to timing and send data
				Thread AutoSendTimeTh = new Thread(new ThreadStart(AutoSendIntervalThFun));
				AutoSendTimeTh.Start();
			}
			else
			{	//else send once
				MyComm.Write(BytesToWrite);
			}
		}
		
		private void SendFromClosedEventHandler(object sender, EventArgs e)
		{
			SendDataToolStripMenuItem.Enabled = true;
		}
		
		//Auto send interval thread function
		private void AutoSendIntervalThFun()
		{
			long OldIntervalTime = DateTime.Now.Ticks;
			long NowIntervalTime = 0;
			int MsIntervalTime = 0;
			
			MsIntervalTime = (int)(SendDataForm.IntervalTime/1000000) ;
			
			MyComm.Write(BytesToWrite);	
			
			while(SendDataForm.RunSendThread)
			{
				if( 1000000 < SendDataForm.IntervalTime )
				{//the time > 1ms, use sleep() 
					Thread.Sleep(MsIntervalTime);
					MyComm.Write(BytesToWrite);	
				}
				else
				{
					NowIntervalTime = DateTime.Now.Ticks;	
					if( SendDataForm.IntervalTime < NowIntervalTime - OldIntervalTime )
					{
						OldIntervalTime = DateTime.Now.Ticks;
						MyComm.Write(BytesToWrite);
					}
				}
			}
		}
		
		void ReadCountToolStripStatusLabelClick(object sender, EventArgs e)
		{
			ReadCountToolStripStatusLabel.Text = "0" ;			
		}
		
		void 关于ToolStripMenuItemClick(object sender, EventArgs e)
		{
			new AboutForm().ShowDialog();
		}
		
		void ClearRawDataToolStripMenuItemClick(object sender, EventArgs e)
		{
			rxDataShow.Clear();
		}
		
		void CleraChartToolStripMenuItemClick(object sender, EventArgs e)
		{
			DataChart.Series["Voltage"].Points.Clear();
		}
		
		void 显示图形ToolStripMenuItemClick(object sender, EventArgs e)
		{	
			//old version
//			if( !ShowCurveToolStripMenuItem.Checked )
//			{
//				DialogResult ReturnResult = MessageBox.Show("Do you want to show the curve? V1.0 may caurse some Error!\n" +
//			                "此版本实时显示曲线将可能导致接收数据错误或其他未知错误！", "Caution", MessageBoxButtons.YesNo);
//				if( ReturnResult == DialogResult.Yes )
//				{
//					ShowCurve = true ;
//					ShowCurveToolStripMenuItem.ForeColor = Color.Crimson;
//					ShowCurveToolStripMenuItem.Checked = true;	
//					//creat and start the updata curve thread	
//					//MyUpdataCurveTh.StartUpdataCurveTh();
//				}
//			}
//			else
//			{
//				ShowCurve = false ;
//				ShowCurveToolStripMenuItem.ForeColor = Color.Black;
//				ShowCurveToolStripMenuItem.Checked = false ;
//				//stop the updata curve thread	
//				//MyUpdataCurveTh.StopUpadaCurveTh();
//			}
			//new version
			if(ShowCurveToolStripMenuItem.Text.Equals("停止显示曲线"))
			{//start the curve show thread
				MyUpdataCurveTh.StopUpadaCurveTh();
				ShowCurveToolStripMenuItem.Text = "显示曲线";	
			}
			else if(ShowCurveToolStripMenuItem.Text.Equals("显示曲线"))
			{
				MyUpdataCurveTh.StartUpdataCurveTh();
				ShowCurveToolStripMenuItem.Text = "停止显示曲线";	
			}
		}
		
		void ShowHexRdioButtonCheckedChanged(object sender, EventArgs e)
		{
			if(ShowHexRdioButton.Checked)
			{
				DealDataThread.ShowHex = true;
			}
			else
			{
				DealDataThread.ShowHex = false;
			}
		}
		
		void ShowStrRdioButtonCheckedChanged(object sender, EventArgs e)
		{
			if(ShowStrRdioButton.Checked)
			{
				DealDataThread.ShowHex = false;
			}
			else
			{
				DealDataThread.ShowHex = true;
			}
		}
		
		void 暂停显示ToolStripMenuItemClick(object sender, EventArgs e)
		{	
			if(StopShowTextToolStripMenuItem.Text.Equals("暂停显示数据"))
			{
				DealDataThread.TextShowEnable = false;
				StopShowTextToolStripMenuItem.Text = "显示数据";	
			}
			else if(StopShowTextToolStripMenuItem.Text.Equals("显示数据"))
			{
				DealDataThread.TextShowEnable = true;
				StopShowTextToolStripMenuItem.Text = "暂停显示数据";	
			}
		}
		
		void MainFormLoad(object sender, EventArgs e)
		{
			MainToolTip.SetToolTip(DataChart, 
			                       "曲线仅提供直观显示，不保证数据的精度\n" +
			                       "持续显示曲线将会造成界面停止响应，建议只查看1000点左右曲线，\n" +
			                       "查看完毕请立即停止曲线显示");
		}
		
		void PointsComboBoxSelectedIndexChanged(object sender, EventArgs e)
		{//select the points wants to showed on curve
			try
			{
				NumberOfCurvePoint = long.Parse(PointsComboBox.Text);
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.ToString());
			}
			if(4000<NumberOfCurvePoint)
			{//if the number bigger then 6000 warning the user
				DialogResult dr = MessageBox.Show("如此多的数据动态实时显示，还是放弃吧少年！否则卡巴死机你！",
					                                  "Warning",MessageBoxButtons.YesNo);
				if(dr == DialogResult.Yes)
				{
					NumberOfCurvePoint = 800;
					PointsComboBox.SelectedIndex = 2;
					DataChart.Series["Voltage"].Points.Clear();		//clear the curve
					return ;
				}
			}
			DataChart.Series["Voltage"].Points.Clear();	//clear the curve
		}
		
		void PointsComboBoxKeyPress(object sender, KeyPressEventArgs e)
		{
			if(e.KeyChar == (char)(Keys.Enter))
			{//select the user defined points number wants to showed on curve
				try
				{
					NumberOfCurvePoint = long.Parse(PointsComboBox.Text);
				}
				catch(Exception ex)
				{
					MessageBox.Show(ex.ToString());
				}
				if( NumberOfCurvePoint < 0 )
				{//if number < 0 pop error
					MessageBox.Show("别逗了，怎么可能出现负点数！","Error");
					NumberOfCurvePoint = 800;
					PointsComboBox.SelectedIndex = 2;
					return ;
				}
				if( 8000 < NumberOfCurvePoint )
				{//if bigger then 8000 points, pop warning
					DialogResult dr = MessageBox.Show("如此多的数据动态实时显示，还是放弃吧少年！否则卡巴死机你！",
					                                  "Warning",MessageBoxButtons.YesNo);
					if(dr == DialogResult.Yes)
					{//give up, reset the para
						NumberOfCurvePoint = 800;
						PointsComboBox.SelectedIndex = 2;
						DataChart.Series["Voltage"].Points.Clear();
						return ;
					}
				}
				DataChart.Series["Voltage"].Points.Clear();
			}
		}
	}
}

